use dashmap::DashMap;
use std::sync::Arc;
use std::time::{Duration, Instant};
use tracing::{debug, info};

/// 消息缓存，用于防止重复处理企业微信消息
#[derive(Clone)]
pub struct MessageCache {
    cache: Arc<DashMap<String, Instant>>,
    ttl: Duration,
}

impl MessageCache {
    /// 创建新的消息缓存
    /// 
    /// # Arguments
    /// * `ttl_seconds` - 缓存过期时间（秒），建议设置为 300 秒（5分钟）
    pub fn new(ttl_seconds: u64) -> Self {
        Self {
            cache: Arc::new(DashMap::new()),
            ttl: Duration::from_secs(ttl_seconds),
        }
    }

    /// 检查消息是否已在处理中
    /// 
    /// # Returns
    /// * `true` - 消息已在处理中，应该忽略
    /// * `false` - 消息未在处理，可以处理
    pub fn is_processing(&self, msgid: &str) -> bool {
        if let Some(entry) = self.cache.get(msgid) {
            let elapsed = entry.value().elapsed();
            if elapsed < self.ttl {
                debug!(
                    "Message {} is already being processed (elapsed: {:?})",
                    msgid, elapsed
                );
                return true;
            } else {
                // 过期条目，删除
                drop(entry);
                self.cache.remove(msgid);
            }
        }
        false
    }

    /// 标记消息为处理中
    pub fn mark_processing(&self, msgid: &str) {
        self.cache.insert(msgid.to_string(), Instant::now());
        debug!("Marked message {} as processing", msgid);
    }

    /// 删除消息（处理完成）
    pub fn remove(&self, msgid: &str) {
        if self.cache.remove(msgid).is_some() {
            debug!("Removed message {} from cache", msgid);
        }
    }

    /// 清理过期的缓存条目
    pub fn cleanup_expired(&self) {
        let expired_keys: Vec<String> = self
            .cache
            .iter()
            .filter(|entry| entry.value().elapsed() >= self.ttl)
            .map(|entry| entry.key().clone())
            .collect();

        if !expired_keys.is_empty() {
            info!("Cleaning up {} expired cache entries", expired_keys.len());
            for key in expired_keys {
                self.cache.remove(&key);
            }
        }
    }

    /// 获取当前缓存大小
    pub fn len(&self) -> usize {
        self.cache.len()
    }

    /// 检查缓存是否为空
    pub fn is_empty(&self) -> bool {
        self.cache.is_empty()
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::thread::sleep;

    #[test]
    fn test_message_cache() {
        let cache = MessageCache::new(1); // 1秒过期

        // 测试首次处理
        assert!(!cache.is_processing("msg1"));
        cache.mark_processing("msg1");
        assert!(cache.is_processing("msg1"));

        // 测试删除
        cache.remove("msg1");
        assert!(!cache.is_processing("msg1"));

        // 测试过期
        cache.mark_processing("msg2");
        assert!(cache.is_processing("msg2"));
        sleep(Duration::from_secs(2));
        assert!(!cache.is_processing("msg2")); // 已过期
    }

    #[test]
    fn test_cleanup_expired() {
        let cache = MessageCache::new(1);
        
        cache.mark_processing("msg1");
        cache.mark_processing("msg2");
        assert_eq!(cache.len(), 2);

        sleep(Duration::from_secs(2));
        cache.cleanup_expired();
        assert_eq!(cache.len(), 0);
    }
}
